package com.mm.serivce.book.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mm.base.constant.BookConstants;
import com.mm.domain.book.DBookInfo;
import com.mm.domain.book.DBookSource;
import com.mm.mapper.book.DBookInfoMapper;
import com.mm.mapper.book.DBookSourceMapper;
import com.mm.serivce.book.BookInfoService;
import com.mm.serivce.book.BookSourceService;
import com.mm.util.common.BookUtil;
import com.mm.util.result.DResult;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description
 * @Date 2023/10/11 上午11:54
 * @Author yanglin
 **/
@Slf4j
@Service
public class BookSourceServiceImpl extends ServiceImpl<DBookSourceMapper, DBookSource> implements BookSourceService {
    private final DBookSourceMapper bookSourceMapper;
    private final DBookInfoMapper bookInfoMapper;
    private final BookInfoService bookInfoService;

    public BookSourceServiceImpl(DBookSourceMapper bookSourceMapper, DBookInfoMapper bookInfoMapper, BookInfoService bookInfoService) {
        this.bookSourceMapper = bookSourceMapper;
        this.bookInfoMapper = bookInfoMapper;
        this.bookInfoService = bookInfoService;
    }

    @Override
    public Page<DBookSource> queryBookSourcePage(Integer page, Integer limit, String sourceTxt) {
        Page<DBookSource> sourceIPage = new Page<>(page, limit);
        LambdaQueryWrapper<DBookSource> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(sourceTxt)) {
            queryWrapper.like(DBookSource::getSourceTitle, sourceTxt);
        }
        sourceIPage = bookSourceMapper.selectPage(sourceIPage, queryWrapper);
        return sourceIPage;
    }

    @Override
    public DBookSource queryBookSourceOne(Long sourceId) {
        DBookSource bookSource = new DBookSource();
        if (sourceId > 0) {
            bookSource = bookSourceMapper.selectById(sourceId);
        }
        return bookSource;
    }

    @Override
    public boolean removeBookSource(Long sourceId) {
        boolean flag = false;
        DBookSource bookSource = bookSourceMapper.selectById(sourceId);
        if (Objects.nonNull(bookSource)) {
            int result = bookSourceMapper.deleteById(bookSource.getSourceId());
            if (result > 0) {
                flag = true;
            }
        }
        return flag;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void crawlingCategoryBook(Long sourceId, Integer page) {
        int size = 0;
        DBookSource bookSource = bookSourceMapper.selectById(sourceId);
        if (Objects.isNull(bookSource)) {
            return;
        }
        List<DBookInfo> analyzeBookList = new ArrayList<>();
        List<String> pageUrls = buildPageUrl(bookSource, page);
        String webMd5 = DigestUtil.md5Hex(bookSource.getSourceUrl());
        // https://www.ishuquge.la/category/1_1.html
        if (BookConstants.BOOK_I_SHU_QU_GE.getMsg().equals(webMd5)) {
            analyzeBookList = analyzeShuQuGeBook(bookSource, pageUrls);
        }
        // http://www.mianhuatang.tw/mulu/2-1.html
        else if (BookConstants.BOOK_MAIN_HUA_TANG.getMsg().equals(webMd5)) {
            analyzeBookList = analyzeMainHuaTangBook(bookSource, pageUrls);
        }
        // http://www.bookben.org/class/xuanhuan/1/
        else if (BookConstants.BOOK_SHU_BEN.getMsg().equals(webMd5)) {
            analyzeBookList = analyzeShuBenBook(bookSource, pageUrls);
        }
        // http://www.janpn.net/wuxiaxiuzhen/list-2-1.html
        else if (BookConstants.BOOK_JAB_PN.getMsg().equals(webMd5)) {
            analyzeBookList = analyzeJanPnBook(bookSource, pageUrls);
        }
        // https://www.qisu12.com/sort/1/1/
        else if (BookConstants.BOOK_QI_SU_12.getMsg().equals(webMd5)) {
            if (bookSource.getSourceCategory() == 100) {
                analyzeBookList = analyzeQiSu12LastUpdateBook(bookSource);
            } else {
                analyzeBookList = analyzeQiSu12Book(bookSource, pageUrls);
            }
        }
        if (CollectionUtil.isNotEmpty(analyzeBookList)) {
            size = analyzeBookList.size();
            bookInfoService.saveOrUpdateBatch(analyzeBookList);
        }
        log.info("crawlingCategoryBook end size:{}", size);
    }

    @Override
    public void crawlingAllBook(Integer page) {
        LambdaQueryWrapper<DBookSource> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DBookSource::isSourceState, true);
        List<DBookSource> bookSourceList = bookSourceMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(bookSourceList)) {
            return;
        }
        int size = 0;
        for (DBookSource bookSource : bookSourceList) {
            List<DBookInfo> analyzeBookList = new ArrayList<>();
            List<String> pageUrls = buildPageUrl(bookSource, page);
            String webMd5 = DigestUtil.md5Hex(bookSource.getSourceUrl());
            log.info("analyze book url: {}", bookSource.getSourceCrawlPath());
            // https://www.ishuquge.la/category/1_1.html
            if (BookConstants.BOOK_I_SHU_QU_GE.getMsg().equals(webMd5)) {
                analyzeBookList = analyzeShuQuGeBook(bookSource, pageUrls);
            }
            // http://www.mianhuatang.tw/mulu/2-1.html
            else if (BookConstants.BOOK_MAIN_HUA_TANG.getMsg().equals(webMd5)) {
                analyzeBookList = analyzeMainHuaTangBook(bookSource, pageUrls);
            }
            // http://www.bookben.org/class/xuanhuan/1/
            else if (BookConstants.BOOK_SHU_BEN.getMsg().equals(webMd5)) {
                analyzeBookList = analyzeShuBenBook(bookSource, pageUrls);
            }
            // http://www.janpn.net/wuxiaxiuzhen/list-2-1.html
            else if (BookConstants.BOOK_JAB_PN.getMsg().equals(webMd5)) {
                analyzeBookList = analyzeJanPnBook(bookSource, pageUrls);
            }
            // https://www.qisu12.com/sort/1/1/
            else if (BookConstants.BOOK_QI_SU_12.getMsg().equals(webMd5)) {
                if (bookSource.getSourceCategory() == 100) {
                    analyzeBookList = analyzeQiSu12LastUpdateBook(bookSource);
                } else {
                    analyzeBookList = analyzeQiSu12Book(bookSource, pageUrls);
                }
            }
            if (CollectionUtil.isNotEmpty(analyzeBookList)) {
                size += analyzeBookList.size();
                bookInfoService.saveOrUpdateBatch(analyzeBookList);
            }
        }
        log.info("crawlingAllBook end size:{}", size);
    }

    /**
     * 解析书趣阁小说列表
     *
     * @param bookSource
     * @return
     */
    private List<DBookInfo> analyzeShuQuGeBook(DBookSource bookSource, List<String> pageUrls) {
        List<DBookInfo> bookInfoList = new ArrayList<>();
        String webUrl = bookSource.getSourceUrl();
        for (String address : pageUrls) {
            // 页面内容
            Document document = BookUtil.getBookSourceDocument(address, bookSource.getSourceUrl());
            if (Objects.isNull(document)) {
                log.error("analyzeShuQuGeBook category document not data...");
                continue;
            }
            // 小说列表
            Elements elements = document.select("li");
            if (CollectionUtil.isEmpty(elements)) {
                log.error("analyzeShuQuGeBook category not data...");
                continue;
            }
            DBookInfo bookInfo;
            for (Element element : elements) {
                try {
                    if (element.children().size() < 4) {
                        continue;
                    }
                    String bookTitle = "";
                    String bookUrl = "";
                    Elements bookTitleEle = element.getElementsByClass("s2");
                    if (CollectionUtil.isNotEmpty(bookTitleEle)) {
                        bookTitle = bookTitleEle.get(0).text();
                        bookUrl = bookTitleEle.get(0).getElementsByTag("a").attr("href");
                    }
                    String lastUpdateChapter = "";
                    String lastUpdateChapterUrl = "";
                    Elements lastUpdateChapterEle = element.getElementsByClass("s3");
                    if (CollectionUtil.isNotEmpty(lastUpdateChapterEle)) {
                        lastUpdateChapter = lastUpdateChapterEle.get(0).text();
                        if (StrUtil.isNotBlank(bookUrl) && StrUtil.isBlank(webUrl)) {
                            webUrl = bookUrl.substring(0, bookUrl.indexOf("/txt"));
                        }
                        lastUpdateChapterUrl = webUrl + lastUpdateChapterEle.get(0).getElementsByTag("a").attr("href");
                    }
                    String bookAuthor = "";
                    Elements bookAuthorEle = element.getElementsByClass("s4");
                    if (CollectionUtil.isNotEmpty(bookAuthorEle)) {
                        bookAuthor = bookAuthorEle.get(0).text();
                    }
                    String updateTime = DateUtil.format(DateUtil.date(), "MM-dd");
                    Elements updateTimeEle = element.getElementsByClass("s5");
                    if (CollectionUtil.isNotEmpty(updateTimeEle)) {
                        updateTime = updateTimeEle.get(0).text();
                    }
                    Date lastUpdateTime = DateUtil.parse("2023-" + updateTime);
                    // 小说唯一标识(小说地址+标题+作者MD5)
                    String bookUnique = DigestUtil.md5Hex(bookTitle + bookAuthor);
                    LambdaQueryWrapper<DBookInfo> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(DBookInfo::getBookUnique, bookUnique);
                    DBookInfo existBook = bookInfoMapper.selectOne(queryWrapper);
                    if (Objects.nonNull(existBook)) {
                        bookInfo = existBook;
                    } else {
                        bookInfo = new DBookInfo();
                        bookInfo.setSourceId(bookSource.getSourceId());
                    }
                    bookInfo.setBookUnique(bookUnique);
                    bookInfo.setBookTitle(bookTitle);
                    bookInfo.setBookWeb(bookSource.getSourceWeb());
                    bookInfo.setBookUrl(bookUrl);
                    bookInfo.setBookCategory(bookSource.getSourceCategory());
                    bookInfo.setLastUpdateChapter(lastUpdateChapter);
                    bookInfo.setLastUpdateChapterUrl(lastUpdateChapterUrl);
                    bookInfo.setBookAuthor(bookAuthor);
                    bookInfo.setLastUpdateTime(lastUpdateTime);
                    bookInfoList.add(bookInfo);
                } catch (Exception e) {
                    log.error("analyzeBookList error : {}", e.getMessage());
                }
            }
        }
        return bookInfoList;
    }

    /**
     * 解析棉花糖小说列表
     *
     * @param bookSource
     * @return
     */
    private List<DBookInfo> analyzeMainHuaTangBook(DBookSource bookSource, List<String> pageUrls) {
        List<DBookInfo> bookInfoList = new ArrayList<>();
        for (String address : pageUrls) {
            // 页面内容
            Document document = BookUtil.getBookSourceDocument(address, bookSource.getSourceUrl());
            if (Objects.isNull(document)) {
                log.error("analyzeMainHuaTangBook category document not data...");
                continue;
            }
            // 小说列表
            Elements elements = document.getElementsByClass("alistbox");
            if (CollectionUtil.isEmpty(elements)) {
                log.error("analyzeMainHuaTangBook category not data...");
                continue;
            }
            DBookInfo bookInfo;
            for (Element element : elements) {
                try {
                    String bookTitle = "";
                    String bookAuthor = "";
                    Elements bookTitleEle = element.getElementsByClass("title");
                    if (CollectionUtil.isNotEmpty(bookTitleEle)) {
                        bookTitle = bookTitleEle.get(0).getElementsByTag("h2").text();
                        if (StrUtil.isNotBlank(bookTitle)) {
                            bookTitle = bookTitle.replace("《", "").replace("》", "");
                        }
                        bookAuthor = bookTitleEle.get(0).getElementsByTag("span").text();
                        if (StrUtil.isNotBlank(bookAuthor)) {
                            bookAuthor = bookAuthor.substring(bookAuthor.indexOf("："));
                        }
                    }
                    String bookUrl = "";
                    String bookImg = "";
                    Elements bookImgEle = element.getElementsByClass("pic");
                    if (CollectionUtil.isNotEmpty(bookImgEle)) {
                        bookUrl = bookImgEle.get(0).getElementsByTag("a").attr("href");
                        bookImg = bookImgEle.get(0).getElementsByTag("img").attr("src");
                    }
                    String bookIntro = "";
                    Elements elementIntros = element.getElementsByClass("intro");
                    if (CollectionUtil.isNotEmpty(elementIntros)) {
                        bookIntro = elementIntros.get(0).text();
                    }
                    String lastUpdateChapter = "";
                    String lastUpdateChapterUrl = "";
                    Elements lastUpdateChapterEle = element.getElementsByClass("sys");
                    if (CollectionUtil.isNotEmpty(lastUpdateChapterEle)) {
                        lastUpdateChapter = lastUpdateChapterEle.get(0).text();
                        if (StrUtil.isNotBlank(lastUpdateChapter)) {
                            lastUpdateChapter = lastUpdateChapter.substring(lastUpdateChapter.indexOf("："));
                        }
                        lastUpdateChapterUrl = lastUpdateChapterEle.get(0).getElementsByTag("a").attr("href");
                    }
                    // 小说唯一标识(小说地址+标题+作者MD5)
                    String bookUnique = DigestUtil.md5Hex(bookTitle + bookAuthor);
                    LambdaQueryWrapper<DBookInfo> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(DBookInfo::getBookUnique, bookUnique);
                    DBookInfo existBook = bookInfoMapper.selectOne(queryWrapper);
                    if (Objects.nonNull(existBook)) {
                        bookInfo = existBook;
                    } else {
                        bookInfo = new DBookInfo();
                        bookInfo.setSourceId(bookSource.getSourceId());
                    }
                    bookInfo.setBookUnique(bookUnique);
                    bookInfo.setBookTitle(bookTitle);
                    bookInfo.setBookWeb(bookSource.getSourceWeb());
                    bookInfo.setBookCategory(bookSource.getSourceCategory());
                    bookInfo.setBookUrl(bookUrl);
                    bookInfo.setBookImg(bookImg);
                    bookInfo.setBookIntro(bookIntro);
                    bookInfo.setLastUpdateChapter(lastUpdateChapter);
                    bookInfo.setLastUpdateChapterUrl(lastUpdateChapterUrl);
                    bookInfo.setBookAuthor(bookAuthor);
                    bookInfo.setLastUpdateTime(DateUtil.date());
                    bookInfoList.add(bookInfo);
                } catch (Exception e) {
                    log.error("analyzeMainHuaTangBook error : {}", e.getMessage());
                }
            }
        }
        return bookInfoList;
    }


    /**
     * 解析书本网小说列表
     *
     * @param bookSource
     * @return
     */
    private List<DBookInfo> analyzeShuBenBook(DBookSource bookSource, List<String> pageUrls) {
        String webUrl = bookSource.getSourceUrl();
        List<DBookInfo> bookInfoList = new ArrayList<>();
        for (String address : pageUrls) {
            // 页面内容
            Document document = BookUtil.getBookSourceDocument(address, bookSource.getSourceUrl());
            if (Objects.isNull(document)) {
                log.error("analyzeShuBenBook category document not data...");
                continue;
            }
            // 小说列表
            Elements elements = document.select("dl");
            if (CollectionUtil.isEmpty(elements)) {
                log.error("analyzeShuBenBook category not data...");
                continue;
            }
            DBookInfo bookInfo;
            for (Element element : elements) {
                try {
                    Elements elementsChildren = element.children();
                    String bookTitle = "";
                    String bookUrl = "";
                    String bookImg = "";
                    Elements bookTitleEle = element.getElementsByClass("imgdd");
                    if (CollectionUtil.isNotEmpty(bookTitleEle)) {
                        bookTitle = bookTitleEle.get(0).getElementsByTag("a").attr("title");
                        bookUrl = webUrl + bookTitleEle.get(0).getElementsByTag("a").attr("href");
                        bookImg = bookTitleEle.get(0).getElementsByTag("img").attr("src");
                    }
                    // String bookCategory = elementsChildren.get(2).text();
                    String bookAuthor = elementsChildren.get(3).text();
                    if (StrUtil.isNotBlank(bookAuthor)) {
                        bookAuthor = bookAuthor.substring(bookAuthor.indexOf("："));
                    }
                    int bookSize = 0;
                    String bookSizeStr = elementsChildren.get(4).text();
                    if (StrUtil.isNotBlank(bookSizeStr)) {
                        bookSizeStr = bookSizeStr.substring(bookSizeStr.indexOf("：") + 1);
                        if (bookSizeStr.contains("万")) {
                            bookSizeStr = bookSizeStr.substring(0, bookSizeStr.indexOf("万"));
                            // 1KB=1024个字节 也就是512个汉字
                            int number = Integer.valueOf(bookSizeStr);
                            // BigDecimal wordsNum = BigDecimal.valueOf(number).divide(BigDecimal.valueOf(512), 0, BigDecimal.ROUND_HALF_UP);
                            bookSize = number;
                        }
                    }
                    // 小说唯一标识(小说地址+标题+作者MD5)
                    String bookUnique = DigestUtil.md5Hex(bookTitle + bookAuthor);
                    LambdaQueryWrapper<DBookInfo> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(DBookInfo::getBookUnique, bookUnique);
                    DBookInfo existBook = bookInfoMapper.selectOne(queryWrapper);
                    if (Objects.nonNull(existBook)) {
                        bookInfo = existBook;
                    } else {
                        bookInfo = new DBookInfo();
                        bookInfo.setSourceId(bookSource.getSourceId());
                    }
                    bookInfo.setBookUnique(bookUnique);
                    bookInfo.setBookTitle(bookTitle);
                    bookInfo.setBookWeb(bookSource.getSourceWeb());
                    bookInfo.setBookImg(bookImg);
                    bookInfo.setBookCategory(bookSource.getSourceCategory());
                    bookInfo.setBookAuthor(bookAuthor);
                    bookInfo.setBookSize(bookSize);
                    bookInfo.setLastUpdateTime(DateUtil.date());
                    bookInfoList.add(bookInfo);
                } catch (Exception e) {
                    log.error("analyzeShuBenBook error : {}", e.getMessage());
                }
            }
        }
        return bookInfoList;
    }

    /**
     * 解析键盘网小说列表
     *
     * @param bookSource
     * @return
     */
    private List<DBookInfo> analyzeJanPnBook(DBookSource bookSource, List<String> pageUrls) {
        // http://www.janpn.net/wuxiaxiuzhen/list-2-1.html
        List<DBookInfo> bookInfoList = new ArrayList<>();
        for (String address : pageUrls) {
            // 页面内容
            Document document = BookUtil.getBookSourceDocument(address, bookSource.getSourceUrl());
            if (Objects.isNull(document)) {
                log.error("analyzeJanPnBook category document not data...");
                continue;
            }
            // 小说列表
            Elements elements = document.getElementsByClass("list").get(0).children();
            if (CollectionUtil.isEmpty(elements)) {
                log.error("analyzeJanPnBook category not data...");
                continue;
            }
            DBookInfo bookInfo;
            for (Element element : elements) {
                try {
                    String bookTitle = element.attr("title");
                    String bookUrl = element.attr("href");
                    // 进入小说明细页面
                    String bookIntro = "";
                    if (StrUtil.isNotBlank(bookUrl)) {
                        Document downloadInputDocument = BookUtil.getBookSourceDocument(bookUrl, bookSource.getSourceUrl());
                        // 下载页面地址
                        Elements downloadUpdateElements = downloadInputDocument.getElementsByClass("col-lg-8");
                        bookUrl = downloadUpdateElements.get(0).getElementsByTag("a").attr("href");
                        // 简介
                        Elements downloadInputElements = downloadInputDocument.getElementsByClass("text-muted bookIntro");
                        bookIntro = downloadInputElements.text();
                    }
                    String bookAuthor = element.children().get(1).text();
                    String lastUpdateChapter = element.children().get(2).text();
                    // 小说唯一标识(小说地址+标题+作者MD5)
                    String bookUnique = DigestUtil.md5Hex(bookTitle + bookAuthor);
                    LambdaQueryWrapper<DBookInfo> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(DBookInfo::getBookUnique, bookUnique);
                    DBookInfo existBook = bookInfoMapper.selectOne(queryWrapper);
                    if (Objects.nonNull(existBook)) {
                        bookInfo = existBook;
                    } else {
                        bookInfo = new DBookInfo();
                        bookInfo.setSourceId(bookSource.getSourceId());
                    }
                    bookInfo.setBookUnique(bookUnique);
                    bookInfo.setBookTitle(bookTitle);
                    bookInfo.setBookUrl(bookUrl);
                    bookInfo.setBookAuthor(bookAuthor);
                    bookInfo.setBookWeb(bookSource.getSourceWeb());
                    bookInfo.setBookIntro(bookIntro);
                    bookInfo.setBookCategory(bookSource.getSourceCategory());
                    bookInfo.setLastUpdateChapter(lastUpdateChapter);
                    bookInfo.setBookAuthor(bookAuthor);
                    bookInfo.setLastUpdateTime(DateUtil.date());
                    bookInfoList.add(bookInfo);
                } catch (Exception e) {
                    log.error("analyzeJanPnBook error : {}", e.getMessage());
                }
            }
        }
        return bookInfoList;
    }

    /**
     * 解析奇书网12小说列表
     *
     * @param bookSource
     * @return
     */
    private List<DBookInfo> analyzeQiSu12Book(DBookSource bookSource, List<String> pageUrls) {
        // https://www.qisu12.com/sort/1/1/
        String webUrl = bookSource.getSourceUrl();
        List<DBookInfo> bookInfoList = new ArrayList<>();
        for (String address : pageUrls) {
            // 页面内容
            Document document = BookUtil.getBookSourceDocument(address, bookSource.getSourceUrl());
            if (Objects.isNull(document)) {
                log.error("analyzeQiSu12Book category document not data...");
                continue;
            }
            // 小说列表
            Elements qiSuElements = document.getElementsByClass("flex");
            if (CollectionUtil.isEmpty(qiSuElements)) {
                log.error("analyzeQiSu12Book category not data...");
                continue;
            }
            List<Element> elementList = qiSuElements.get(0).children().stream().distinct().collect(Collectors.toList());
            DBookInfo bookInfo;
            for (Element element : elementList) {
                try {
                    String bookUrl = element.getElementsByTag("a").attr("href");
                    String bookImg = element.getElementsByTag("img").attr("data-original");
                    String bookTitle = element.getElementsByTag("img").attr("title");
                    bookTitle = StrUtil.trim(bookTitle);
                    String bookIntro = element.getElementsByTag("p").text();
                    if (StrUtil.isNotBlank(bookUrl)) {
                        bookUrl = webUrl + bookUrl;
                    }
                    Elements var2 = element.getElementsByClass("li_bottom");
                    List<Element> elementListVar3 = var2.get(0).children().stream().distinct().collect(Collectors.toList());
                    String bookAuthor = elementListVar3.get(0).getElementsByTag("a").text();
                    bookAuthor = StrUtil.trim(bookAuthor);
                    int bookSize = 0;
                    String bookSizeStr = elementListVar3.get(1).getElementsByTag("em").text();
                    if (StrUtil.isNotBlank(bookSizeStr)) {
                        if (bookSizeStr.contains("万")) {
                            bookSizeStr = bookSizeStr.substring(0, bookSizeStr.indexOf("万"));
                            // 1KB=1024个字节 也就是512个汉字
                            int number = Integer.valueOf(bookSizeStr);
                            // BigDecimal wordsNum = BigDecimal.valueOf(number).divide(BigDecimal.valueOf(512), 0, BigDecimal.ROUND_HALF_UP);
                            bookSize = number;
                        }
                    }
                    // 小说唯一标识(小说地址+标题+作者MD5)
                    String bookUnique = DigestUtil.md5Hex(bookTitle + bookAuthor);
                    LambdaQueryWrapper<DBookInfo> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(DBookInfo::getBookUnique, bookUnique);
                    List<DBookInfo> existBooks = bookInfoMapper.selectList(queryWrapper);
                    if (CollectionUtil.isNotEmpty(existBooks)) {
                        bookInfo = existBooks.get(0);
                        if (existBooks.size() > 1) {
                            existBooks.remove(0);
                            DBookInfo finalBookInfo = bookInfo;
                            existBooks.removeIf(b -> b.getBookId().equals(finalBookInfo.getBookId()));
                            List<Long> repeatBookIds = existBooks.stream().map(DBookInfo::getBookId).collect(Collectors.toList());
                            int deleteNum = bookInfoMapper.deleteBatchIds(repeatBookIds);
                            log.info("repeat book info : {} {} bookUnique : {} deleteNum : {}", bookTitle, bookAuthor, bookUnique, deleteNum);
                        }
                    } else {
                        bookInfo = new DBookInfo();
                        bookInfo.setSourceId(bookSource.getSourceId());
                    }
                    bookInfo.setBookUnique(bookUnique);
                    bookInfo.setBookTitle(bookTitle);
                    bookInfo.setBookUrl(bookUrl);
                    bookInfo.setBookImg(bookImg);
                    bookInfo.setBookAuthor(bookAuthor);
                    bookInfo.setBookSize(bookSize);
                    bookInfo.setBookWeb(bookSource.getSourceWeb());
                    bookInfo.setBookIntro(bookIntro);
                    bookInfo.setBookCategory(bookSource.getSourceCategory());
                    bookInfo.setLastUpdateTime(DateUtil.date());
                    bookInfoList.add(bookInfo);
                } catch (Exception e) {
                    log.error("analyzeQiSu12Book error : {}", e.getMessage());
                }
            }
        }
        return bookInfoList;
    }

    /**
     * 解析奇书网12-最新章节小说列表
     *
     * @param bookSource
     * @return
     */
    private List<DBookInfo> analyzeQiSu12LastUpdateBook(DBookSource bookSource) {
        // https://www.qisu12.com/sort/1/1/
        String webUrl = bookSource.getSourceUrl();
        List<DBookInfo> bookInfoList = new ArrayList<>();
        // 页面内容
        Document document = BookUtil.getBookSourceDocument(bookSource.getSourceCrawlPath(), bookSource.getSourceUrl());
        if (Objects.isNull(document)) {
            log.error("analyzeQiSu12LastUpdateBook document not data...");
            return bookInfoList;
        }
        // 最新章节
        Elements qiSuLastUpdateElements = document.getElementsByClass("lastupdate");
        if (CollectionUtil.isNotEmpty(qiSuLastUpdateElements)) {
            List<Element> elementList = qiSuLastUpdateElements.get(0).getElementsByTag("li");
            DBookInfo bookInfo;
            for (Element element : elementList) {
                try {
                    Elements infoElements = element.children();
                    Integer bookCategory = 10;
                    String bookCategoryStr = infoElements.get(0).text();
                    if (StrUtil.isNotBlank(bookCategoryStr)) {
                        bookCategoryStr = bookCategoryStr.replace("「","").replace("」","");
                        if ("其他".equals(bookCategoryStr)) {
                            bookCategory = 90;
                        } else if ("游戏".equals(bookCategoryStr)) {
                            bookCategory = 50;
                        } else if ("武侠".equals(bookCategoryStr)) {
                            bookCategory = 20;
                        } else if ("玄幻".equals(bookCategoryStr)) {
                            bookCategory = 10;
                        } else if ("科幻".equals(bookCategoryStr)) {
                            bookCategory = 60;
                        } else if ("历史".equals(bookCategoryStr)) {
                            bookCategory = 40;
                        } else if ("都市".equals(bookCategoryStr)) {
                            bookCategory = 30;
                        }
                    }
                    String bookTitle = StrUtil.trim(infoElements.get(1).text());
                    String bookUrl = infoElements.get(1).attr("href");
                    String bookDownloadUrl = "";
                    String bookIntro = "";
                    String bookImg = "";
                    String bookState = "";
                    int bookSize = 0;
                    if (StrUtil.isNotBlank(bookUrl)) {
                        bookUrl = webUrl + bookUrl;
                        Document downloadInputDocument = BookUtil.getBookSourceDocument(bookUrl, bookSource.getSourceUrl());
                        // 电子书下载地址
                        Elements downloadUpdateElements = downloadInputDocument.getElementsByClass("l_btn_0");
                        bookDownloadUrl = webUrl + downloadUpdateElements.get(0).getElementsByTag("a").attr("href");
                        // 简介
                        Elements downloadInputElements = downloadInputDocument.getElementsByClass("intro");
                        bookIntro = downloadInputElements.text();
                        Elements detailElements = downloadInputDocument.getElementsByClass("novel_info_main");
                        bookImg = detailElements.get(0).getElementsByTag("img").attr("src");
                        Elements sizeElements = downloadInputDocument.getElementsByClass("novel_info_title");
                        String bookSizeStr = sizeElements.get(0).getElementsByTag("span").get(1).text();
                        bookState = sizeElements.get(0).getElementsByTag("span").get(2).text();
                        if (StrUtil.isNotBlank(bookSizeStr)) {
                            if (bookSizeStr.contains("万")) {
                                bookSizeStr = bookSizeStr.substring(0, bookSizeStr.indexOf("万")).trim();
                                // 1KB=1024个字节 也就是512个汉字
                                int number = Integer.valueOf(bookSizeStr);
                                // BigDecimal wordsNum = BigDecimal.valueOf(number).divide(BigDecimal.valueOf(512), 0, BigDecimal.ROUND_HALF_UP);
                                bookSize = number;
                            }
                        }
                    }
                    String lastUpdateChapter = infoElements.get(2).text();
                    String lastUpdateChapterUrl = infoElements.get(2).attr("href");
                    if (StrUtil.isNotBlank(lastUpdateChapterUrl)) {
                        lastUpdateChapterUrl = webUrl + lastUpdateChapterUrl;
                    }
                    String bookAuthor = infoElements.get(3).text();
                    if (StrUtil.isNotBlank(bookAuthor)) {
                        bookAuthor = bookAuthor.split("  ")[0];
                        bookAuthor = StrUtil.trim(bookAuthor);
                    }
                    // 小说唯一标识(小说地址+标题+作者MD5)
                    String bookUnique = DigestUtil.md5Hex(bookTitle + bookAuthor);
                    LambdaQueryWrapper<DBookInfo> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(DBookInfo::getBookUnique, bookUnique);
                    DBookInfo existBook = bookInfoMapper.selectOne(queryWrapper);
                    if (Objects.nonNull(existBook)) {
                        bookInfo = existBook;
                    } else {
                        bookInfo = new DBookInfo();
                        bookInfo.setSourceId(bookSource.getSourceId());
                    }
                    bookInfo.setBookUnique(bookUnique);
                    bookInfo.setBookTitle(bookTitle);
                    bookInfo.setBookUrl(bookUrl);
                    bookInfo.setBookAuthor(bookAuthor);
                    bookInfo.setBookState(bookState);
                    bookInfo.setBookWeb(bookSource.getSourceWeb());
                    bookInfo.setBookCategory(bookCategory);
                    bookInfo.setBookIntro(bookIntro);
                    bookInfo.setBookImg(bookImg);
                    bookInfo.setBookSize(bookSize);
                    bookInfo.setBookDownloadUrl(bookDownloadUrl);
                    bookInfo.setLastUpdateChapter(lastUpdateChapter);
                    bookInfo.setLastUpdateChapterUrl(lastUpdateChapterUrl);
                    bookInfo.setLastUpdateTime(DateUtil.date());
                    bookInfoList.add(bookInfo);
                } catch (Exception e) {
                    log.error("analyzeQiSu12LastUpdateBook error : {}", e.getMessage());
                }
            }
        }
        return bookInfoList;
    }

    private List<String> buildPageUrl(DBookSource bookSource, int pageNo) {
        List<String> pageUrls = new LinkedList<>();
        StringBuilder page;
        String sourceUrl = bookSource.getSourceUrl();
        String categoryUrl = bookSource.getSourceCrawlPath();
        String webMd5 = DigestUtil.md5Hex(sourceUrl);
        // http://www.mianhuatang.tw/mulu/2-1.html
        if (BookConstants.BOOK_MAIN_HUA_TANG.getMsg().equals(webMd5)) {
            String bookPrefix = categoryUrl.substring(0, categoryUrl.lastIndexOf(".") - 1);
            String bookSuffix = categoryUrl.substring(categoryUrl.lastIndexOf("."));
            for (int i = 1; i <= pageNo; i++) {
                page = new StringBuilder();
                page.append(bookPrefix).append(i).append(bookSuffix);
                pageUrls.add(page.toString());
            }
        }
        // http://www.bookben.org/class/xuanhuan/1/
        else if (BookConstants.BOOK_SHU_BEN.getMsg().equals(webMd5)) {
            String bookPrefix = categoryUrl.substring(0, categoryUrl.lastIndexOf("/") - 1);
            for (int i = 1; i <= pageNo; i++) {
                page = new StringBuilder();
                page.append(bookPrefix).append(i).append("/");
                pageUrls.add(page.toString());
            }
        }
        // http://www.janpn.net/wuxiaxiuzhen/list-2-1.html
        else if (BookConstants.BOOK_JAB_PN.getMsg().equals(webMd5)) {
            String bookPrefix = categoryUrl.substring(0, categoryUrl.lastIndexOf(".") - 1);
            String bookSuffix = categoryUrl.substring(categoryUrl.lastIndexOf("."));
            for (int i = 1; i <= pageNo; i++) {
                page = new StringBuilder();
                page.append(bookPrefix).append(i).append(bookSuffix);
                pageUrls.add(page.toString());
            }
        }
        // https://www.qisu12.com/sort/1/1/
        else if (BookConstants.BOOK_QI_SU_12.getMsg().equals(webMd5)) {
            String bookPrefix = categoryUrl.substring(0, categoryUrl.lastIndexOf("/") - 1);
            for (int i = 1; i <= pageNo; i++) {
                page = new StringBuilder();
                page.append(bookPrefix).append(i).append("/");
                pageUrls.add(page.toString());
            }
        }
        return pageUrls;
    }


    public static void main(String[] args) {
        System.out.println( DigestUtil.md5Hex("https://www.qisu12.com/txt/62371.html这个封神不正常逆子多多"));
    }
}
